import {eduPageSwitch} from './script/core/animation/EduPageSwitch';
import {EduRuntimeTools} from './scene/EduRuntimeTools';
import {BundleLoader, GameConfig, PageInfo} from './script/GameConfig';
import {GameDB} from './script/GameDB';
import EduPage from './script/component/EduPage';
import EduMusic from './script/ui/EduMusic/EduMusic';
import eduMusicMgr from './script/ui/EduMusic/EduMusicMgr';
import {eduClientMode} from './mode/EduClientMode';
import EduEventEntries from './script/core/events/EduEventEntries';
import ActionAnimationEffect, {
    ActionAnimationEffectClassName,
} from './script/core/events/regist/ActionAnimationEffect';

enum EduGameEvent {
    OnInitialize = 'OnInitialize',
    OnPageReadyLoad = 'OnPageReadyLoad',
    OnPageFinishLoad = 'OnPageFinishLoad',
    OnPageAdded = 'OnPageAdded',
    OnPageSwitch = 'OnPageSwitch',
    OnLessonEnd = 'OnLessonEnd',
}

export enum NextPageEvent {
    Default,
    AnyClick,
    Disable,
}

export class EduGame {
    private pageNode: cc.Node = null;
    private touchNode: cc.Node = null;
    private shieldNode: cc.Node = null;

    public curPageInstance: cc.Node = null;
    public Event = EduGameEvent;
    public nextPageEvent: NextPageEvent = NextPageEvent.Default;
    public clientMode = eduClientMode;

    public init() {
        let viewSize = cc.view.getVisibleSize();
        let node = new cc.Node('edu-game');

        let touchNode = new cc.Node('edu-touch');
        this.touchNode = touchNode;
        touchNode.setContentSize(viewSize);
        node.addChild(touchNode, 1);

        let pageNode = new cc.Node('edu-page');
        this.pageNode = pageNode;
        pageNode.setContentSize(viewSize);
        node.addChild(pageNode, 2);

        let shieldNode = new cc.Node('edu-shield');
        this.shieldNode = shieldNode;
        shieldNode.addComponent(cc.BlockInputEvents);
        shieldNode.setContentSize(viewSize);
        node.addChild(shieldNode, 3);

        this._init();
        return node;
    }

    private _init() {
        cc.debug.setDisplayStats(false);
        eduPageSwitch.init(this.pageNode);
        EduRuntimeTools.init({
            previous: () => {
                this.goPreviously();
            },
            next: () => {
                this.goNext();
            },
        });

        this.touchNode.on(
            cc.Node.EventType.TOUCH_START,
            () => {
                switch (this.nextPageEvent) {
                    case NextPageEvent.Default:
                        this.goNext();
                        break;
                    case NextPageEvent.AnyClick:
                        break;
                    case NextPageEvent.Disable:
                        break;
                }
            },
            this,
        );

        GameConfig.loadConfig((data) => {
            this.emitEvent(EduGameEvent.OnInitialize);
        });
    }

    public closePreviewWindow() {
        // const Electron = window.require('electron')
        // Electron.ipcRenderer.sendToHost('closePreview');
        let xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://127.0.0.1:9906/close-preview');
        xhr.send();
    }

    private _event: Record<string, Array<Function>> = {};

    public addEventListener(event: EduGameEvent, cb: Function) {
        if (!this._event.hasOwnProperty(event)) {
            this._event[event] = [];
        }
        this._event[event].push(cb);
        return cb;
    }

    public removeEventListener(event: EduGameEvent, cb: Function) {
        if (this._event.hasOwnProperty(event)) {
            for (let i = 0; i < this._event[event].length;) {
                let func = this._event[event][i];
                if (func === cb) {
                    this._event[event].splice(i, 1);
                } else {
                    i++;
                }
            }
        }
    }

    public cleanEventListener(event: EduGameEvent) {
        if (this._event.hasOwnProperty(event)) {
            this._event[event] = [];
        }
    }

    public resetEventListener() {
        this._event = {};
    }

    public emitEvent(event: EduGameEvent, data?: any) {
        if (this._event.hasOwnProperty(event)) {
            this._event[event].forEach((func) => {
                func && func(data);
            });
        }
    }

    public goPreviously() {
        let info: PageInfo = GameDB.getPreviouslyPage();
        if (info) {
            this._goPage(info);
        }
    }

    public goNext() {
        let info: PageInfo = GameConfig.getNextPage(GameDB.curPageInfo.id);
        if (info) {
            this._goPage(info);
        }
    }

    goPageByID(id) {
        let info: PageInfo = GameConfig.getPageByID(id);
        if (info) {
            this._goPage(info);
        }
    }

    protected _updateBtnEnabled(loading) {
        if (loading) {
            EduRuntimeTools.enabledPreBtn(false);
            EduRuntimeTools.enabledNextBtn(false);
        } else {
            let prev = !!GameDB.hasPreviouslyPage();
            EduRuntimeTools.enabledPreBtn(prev);

            let next = !!GameConfig.getNextPage(GameDB.curPageInfo.id);
            EduRuntimeTools.enabledNextBtn(next);

            let [cur, total] = GameConfig.getPagePositionInfo(GameDB.curPageInfo.id);
            EduRuntimeTools.updateProcess(`[${cur}/${total}]`);
        }
    }

    protected _goPage(info: PageInfo) {
        if (eduPageSwitch.switching) {
            return;
        }

        if (info) {
            this.loadPage(info);
        } else {
            // this._cleanPageNode();
            cc.log('end');
            GameDB.curPageInfo = null;
            this.emitEvent(EduGameEvent.OnLessonEnd, {
                lesson: GameDB.curLessonInfo,
                page: GameDB.curPageInfo,
            });
        }
    }

    protected _cleanPageNode() {
        this.pageNode.destroyAllChildren();
    }

    protected _enabledShield(b) {
        if (this.shieldNode) {
            this.shieldNode.active = !!b;
        }
        this._updateBtnEnabled(b);
    }

    public loadPage(info: PageInfo) {
        this._enabledShield(true);
        info.load((prefab) => {
            GameDB.curPageInfo = info;
            GameDB.pushPage(info);
            this.emitEvent(EduGameEvent.OnPageReadyLoad, {
                lesson: GameDB.curLessonInfo,
                page: GameDB.curPageInfo,
            });
            this._enabledShield(false);

            this.emitEvent(EduGameEvent.OnPageFinishLoad, {
                lesson: GameDB.curLessonInfo,
                page: GameDB.curPageInfo,
            });
            let pagePrefab = cc.instantiate(prefab);
            pagePrefab.x = pagePrefab.y = 0;
            if (this.pageNode) {
                this.curPageInstance = pagePrefab;
                this.pageNode.addChild(pagePrefab);
                this.initShowAction(pagePrefab);
                this.emitEvent(EduGameEvent.OnPageAdded, {
                    lesson: GameDB.curLessonInfo,
                    page: GameDB.curPageInfo,
                });
                eduPageSwitch.setCurPage(pagePrefab);
                let pageLogic: EduPage = pagePrefab.getComponent(EduPage);
                eduPageSwitch.onSwitchPage(pageLogic.pageSwitch, () => {
                    const hasAutoPlayMusic = this._dealAutoPlayMusic(pagePrefab);
                    this.emitEvent(EduGameEvent.OnPageSwitch, {
                        lesson: GameDB.curLessonInfo,
                        page: GameDB.curPageInfo,
                        hasAutoPlayMusic,
                    });
                });
                this.loadRemark();
            }
        });
    }

    private initShowAction(pageNode: cc.Node) {
        // 分析出来对象的第一个动作到底是不是出现类型的，来决定是否要默认隐藏
        let array: Array<EduEventEntries> = [];

        function circle(node) {
            let entries = node.getComponent(EduEventEntries);
            if (entries) {
                array.push(entries);
            }
            node.children.forEach((child) => {
                circle(child);
            });
        }

        circle(pageNode);

        let targetNodesActions: Record<string, Array<ActionAnimationEffect>> = {};
        array.forEach((entries) => {
            entries.analyze();
            if (entries.eventArray.length > 0) {
                entries.eventArray.forEach((eventArray) => {
                    // 这里都是并行执行的事件
                    eventArray.forEach((entry) => {
                        entry.analyzeActions();
                        entry.actionArray.forEach((actionArray) => {
                            // 这里都是并行执行的动作
                            actionArray.forEach((action) => {
                                if (action.type === ActionAnimationEffectClassName) {
                                    const animationEffect: ActionAnimationEffect =
                                        action.action as ActionAnimationEffect;
                                    let targetNode = animationEffect.getTargetNode(false);
                                    if (targetNode) {
                                        const { uuid } = targetNode;
                                        if (!targetNodesActions.hasOwnProperty(uuid)) {
                                            targetNodesActions[uuid] = [];
                                        }
                                        targetNodesActions[uuid].push(animationEffect);
                                    }
                                }
                            });
                        });
                    });
                });
            }
        });

        for (let key in targetNodesActions) {
            if (targetNodesActions.hasOwnProperty(key)) {
                let animationEffects: Array<ActionAnimationEffect> = targetNodesActions[key];
                if (animationEffects.length > 0) {
                    const item = animationEffects[0];
                    item.visibleTarget();
                }
            }
        }
    }

    protected async loadRemark() {
        new BundleLoader('EduRemark', (bundle) => {
            if (bundle) {
                bundle.load('prefab/remark', cc.Prefab, (err: {message: any}, res: any) => {
                    if (err) {
                        cc.error(err.message || err);
                        return;
                    } else {
                        if (!this.pageNode.getChildByName('remark')) {
                            let remarkPrefab = res;
                            let eduRemarkNode = cc.instantiate(remarkPrefab);
                            eduRemarkNode.zIndex = 999;
                            this.pageNode.addChild(eduRemarkNode);
                        }
                    }
                });
            }
        }).load();
    }

    // 产品需求：
    // 如果回到的这页没有自动播放的音频，继续播放没播完的音频
    // 如果回到的这页有自动播放的音频，停止没播完的音频，重新播放新音频
    private _dealAutoPlayMusic(pageNode: cc.Node) {
        let hasAutoPlayMusic = false;
        for (let i = 0; i < pageNode.children.length; i++) {
            let child = pageNode.children[i];
            let eduMusic = child.getComponent(EduMusic);
            if (eduMusic && eduMusic.playSettings.autoPlay) {
                hasAutoPlayMusic = true;
                break;
            }
        }
        if (hasAutoPlayMusic) {
            eduMusicMgr.stopAll();
            cc.audioEngine.stopAllEffects();
        }
        return hasAutoPlayMusic;
    }
}

export let eduGame = new EduGame();
if (!CC_EDITOR) {
    globalThis.edu = {};
    //@ts-ignore
    edu.eduGame = eduGame;
}
